#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"

int main()
{
    int ret = 0;
    // 1.注册所有的设备
    avdevice_register_all();

    // 2.Windows使用dshow
    const AVInputFormat* informat = av_find_input_format("dshow");
    if(!informat) return -1;

    // 3.打开音频设备
    AVFormatContext* fmt_ctx = NULL;    // 没有至为NULL 断言错误
    const char* deviceName = "audio=麦克风 (Realtek(R) Audio)";
    ret = avformat_open_input(&fmt_ctx,deviceName,informat,NULL);
    if(ret < 0) return -1;

    // 4.获取流信息
    av_dump_format(fmt_ctx,0,deviceName,0);

    if(fmt_ctx->nb_streams > 0)
    {
        AVCodecParameters* codecpar = fmt_ctx->streams[0]->codecpar;
        printf("Sample rate : %d\n",codecpar->sample_rate);
        printf("Channels : %d\n",codecpar->ch_layout.nb_channels);
        printf("Sample format : %s\n",av_get_sample_fmt_name(codecpar->format));
        printf("Frame size : %d\n",codecpar->frame_size);
    }

    // 5.将音频存入文件中
    FILE* outFile = fopen("audio.pcm","wb+");

    AVPacket* pkt = av_packet_alloc();
    int count = 0;
    while((ret = av_read_frame(fmt_ctx,pkt)) == 0 && count++ < 30)
    {
        fwrite(pkt->data,pkt->size,1,outFile);
        fflush(outFile);    // TODO 频繁刷新缓冲区！
        printf("pkt size is %d\n",pkt->size);
        av_packet_unref(pkt);
    }
    fclose(outFile);

    // 6.释放资源
    avformat_close_input(&fmt_ctx);
    av_packet_free(&pkt);

    printf("finished\n");

    // 播放命令：ffplay audio.pcm -f s16le -ac 2 -ar 44100

    return 0;
}

/*

#include <stdio.h>
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"

int main()
{
    AVFormatContext* fmt_ctx = NULL;    // 没有至为NULL 断言错误avformat_open_input
    const char* deviceName = "audio=麦克风 (Realtek(R) Audio)";
    char errors[1024] = {0};
    int ret = 0;
    // 注册所有设备
    avdevice_register_all();
    // 获取格式
    const AVInputFormat* iformat = av_find_input_format("dshow");

    ret = avformat_open_input(&fmt_ctx,deviceName,iformat,NULL);

    if(ret < 0)
    {
        av_strerror(ret,errors,1024);
        fprintf(stderr,"Faled to open audio device ,[%d] %s\n",ret,errors);
        return -1;
    }

    if(fmt_ctx->nb_streams > 0) {
        AVCodecParameters* codecpar = fmt_ctx->streams[0]->codecpar;
        printf("Sample rate: %d\n", codecpar->sample_rate);
        printf("Channels: %d\n", codecpar->channels);
        printf("Sample format: %s\n", av_get_sample_fmt_name(codecpar->format));
        printf("Frame size: %d\n", codecpar->frame_size);
    }

    //创建文件
    FILE* outFile = fopen("audio.pcm","wb+");

    // AVPacket pkt;
    // av_init_packet(&pkt); // TODO 接口废弃了？
    AVPacket *pkt = av_packet_alloc();
    int count = 0;
    while((ret = av_read_frame(fmt_ctx,pkt))==0 && count++ < 30)
    {
        // 写入文件
        fwrite(pkt->data,pkt->size,1,outFile);
        fflush(outFile);    // TODO 效率降低！频繁刷新缓冲区

        printf("pkt size is %d\n",pkt->size);
        // release pkt
        av_packet_unref(pkt);
    }

    fclose(outFile);

    avformat_close_input(&fmt_ctx);
    av_packet_free(&pkt);
    avformat_close_input(&fmt_ctx);
    printf("finished\n");


    return 0;
}

*/

/*
#include <stdio.h>
#include <string.h>
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"


int main()
{
    AVFormatContext* fmt_ctx = NULL;
    const char* deviceName = "audio=麦克风 (Realtek(R) Audio)";
    char errors[1024] = {0};
    int ret = 0;

    avdevice_register_all();
    const AVInputFormat* iformat = av_find_input_format("dshow");

    // 设置音频参数
    AVDictionary* options = NULL;
    av_dict_set(&options, "sample_rate", "44100", 0);
    av_dict_set(&options, "channels", "2", 0);
    av_dict_set(&options, "sample_fmt", "s32", 0);
    ret = avformat_open_input(&fmt_ctx, deviceName, iformat, &options);

    if(ret < 0)
    {
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open audio device, [%d] %s\n", ret, errors);
        return -1;
    }

    // 打印音频流信息
    av_dump_format(fmt_ctx, 0, deviceName, 0);

    // 获取实际的音频参数
    if(fmt_ctx->nb_streams > 0) {
        AVCodecParameters* codecpar = fmt_ctx->streams[0]->codecpar;
        printf("Sample rate: %d\n", codecpar->sample_rate);
        printf("Channels: %d\n", codecpar->ch_layout.nb_channels);
        printf("Sample format: %s\n", av_get_sample_fmt_name(codecpar->format));
        printf("Frame size: %d\n", codecpar->frame_size);
    }

    FILE* outFile = fopen("audio.acc", "wb+");
    AVPacket *pkt = av_packet_alloc();
    int count = 0;

    // 重采样
    SwrContext* swr_ctx = NULL;
    // swr_alloc_set_opts2()
    swr_ctx = swr_alloc_set_opts(NULL,
                                 AV_CH_LAYOUT_STEREO,
                                 AV_SAMPLE_FMT_S16,
                                 44100,
                                 AV_CH_LAYOUT_STEREO,
                                 AV_SAMPLE_FMT_FLT,
                                 44100,
                                 0,NULL);

    if(!swr_ctx)
    {
        return -1;
    }
    if(swr_init(swr_ctx) < 0)
    {
        return -1;
    }

    uint8_t **src_data = NULL;
    int src_linesize = 0;
    uint8_t **dst_data = NULL;
    int dst_linesize = 0;

    // 创建输入缓冲区
    av_samples_alloc_array_and_samples(&src_data,
                                       &src_linesize,
                                       2,
                                       512,
                                       AV_SAMPLE_FMT_FLT,
                                       0);

    // 创建输出缓冲区
    av_samples_alloc_array_and_samples(&dst_data,
                                       &dst_linesize,
                                       2,
                                       51,
                                       AV_SAMPLE_FMT_S16,
                                       0);

    while((ret = av_read_frame(fmt_ctx, pkt)) == 0 && count++ < 100) // 多采集一些帧
    {
        memcpy((void*)src_data[0],(void*)pkt->data,pkt->size);

        // 重采样
        swr_convert(swr_ctx,
                    dst_data,
                    512,
                    (const uint8_t**)src_data,
                    512);

        //fwrite(pkt->data, pkt->size, 1, outFile);
        fwrite(dst_data[0], 1, dst_linesize, outFile);
        //printf("pkt size is %d, count: %d\n", pkt->size, count);
        fflush(outFile);
        av_packet_unref(pkt);
    }

    fclose(outFile);
    avformat_close_input(&fmt_ctx);
    av_packet_free(&pkt);
    av_dict_free(&options);
    if(src_data)
    {
        av_freep(&src_data[0]);
    }
    av_freep(src_data);

    if(dst_data)
    {
        av_freep(&dst_data[0]);
    }
    av_freep(dst_data);

    swr_free(&swr_ctx);

    printf("finished\n");
    return 0;
}

*/

/*
#include <stdio.h>
#include <string.h>
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"

int main()
{
    AVFormatContext* fmt_ctx = NULL;
    const char* deviceName = "audio=麦克风 (Realtek(R) Audio)";
    char errors[1024] = {0};
    int ret = 0;

    avdevice_register_all();
    const AVInputFormat* iformat = av_find_input_format("dshow");

    // 设置音频参数
    AVDictionary* options = NULL;
    av_dict_set(&options, "sample_rate", "44100", 0);
    av_dict_set(&options, "channels", "2", 0);
    av_dict_set(&options, "sample_fmt", "s16", 0);

    ret = avformat_open_input(&fmt_ctx, deviceName, iformat, &options);

    if(ret < 0)
    {
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open audio device, [%d] %s\n", ret, errors);
        return -1;
    }

    // 打印音频流信息
    av_dump_format(fmt_ctx, 0, deviceName, 0);

    // 获取实际的音频参数
    AVCodecParameters* codecpar = NULL;
    if(fmt_ctx->nb_streams > 0) {
        codecpar = fmt_ctx->streams[0]->codecpar;
        printf("Input audio parameters:\n");
        printf("  Sample rate: %d\n", codecpar->sample_rate);
        printf("  Channels: %d\n", codecpar->ch_layout.nb_channels);
        printf("  Sample format: %s\n", av_get_sample_fmt_name(codecpar->format));
        printf("  Frame size: %d\n", codecpar->frame_size);

        // 打印声道布局信息
        char layout_str[64];
        av_channel_layout_describe(&codecpar->ch_layout, layout_str, sizeof(layout_str));
        printf("  Channel layout: %s\n", layout_str);
    }

    FILE* outFile = fopen("audio_s32.pcm", "wb+");
    AVPacket *pkt = av_packet_alloc();
    int count = 0;

    // 获取输入音频的参数
    enum AVSampleFormat in_sample_fmt = codecpar->format;
    int in_sample_rate = codecpar->sample_rate;
    AVChannelLayout in_ch_layout = codecpar->ch_layout;

    // 设置输出参数：S16 -> S32
    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S32;
    int out_sample_rate = 44100;
    AVChannelLayout out_ch_layout;
    av_channel_layout_default(&out_ch_layout, 2); // 立体声

    printf("Resampling parameters:\n");
    printf("  Input:  sample_fmt=%s, sample_rate=%d, channels=%d\n",
           av_get_sample_fmt_name(in_sample_fmt), in_sample_rate, in_ch_layout.nb_channels);
    printf("  Output: sample_fmt=%s, sample_rate=%d, channels=%d\n",
           av_get_sample_fmt_name(out_sample_fmt), out_sample_rate, out_ch_layout.nb_channels);

    // 创建重采样上下文使用 swr_alloc_set_opts2
    SwrContext* swr_ctx = NULL;
    ret = swr_alloc_set_opts2(&swr_ctx,
                              &out_ch_layout, out_sample_fmt, out_sample_rate,
                              &in_ch_layout, in_sample_fmt, in_sample_rate,
                              0, NULL);

    if(ret < 0 || !swr_ctx)
    {
        fprintf(stderr, "Failed to allocate resampler context\n");
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Error: %s\n", errors);
        return -1;
    }

    if(swr_init(swr_ctx) < 0)
    {
        fprintf(stderr, "Failed to initialize resampler\n");
        return -1;
    }

    // 分配重采样缓冲区
    int max_dst_nb_samples = 1024;
    uint8_t **dst_data = NULL;
    int dst_linesize = 0;

    // 分配输出缓冲区
    ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, out_ch_layout.nb_channels,
                                             max_dst_nb_samples, out_sample_fmt, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate destination samples\n");
        return -1;
    }

    printf("Starting audio capture and resampling (S16 -> S32)...\n");

    while((ret = av_read_frame(fmt_ctx, pkt)) == 0 && count++ < 100)
    {
        // 计算输入样本数
        int src_nb_samples = pkt->size / (av_get_bytes_per_sample(in_sample_fmt) * in_ch_layout.nb_channels);

        if (src_nb_samples <= 0) {
            av_packet_unref(pkt);
            continue;
        }

        // 分配输入样本缓冲区
        uint8_t **src_data = NULL;
        int src_linesize = 0;

        ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, in_ch_layout.nb_channels,
                                                 src_nb_samples, in_sample_fmt, 0);
        if (ret < 0) {
            fprintf(stderr, "Could not allocate source samples for packet %d\n", count);
            av_packet_unref(pkt);
            continue;
        }

        // 拷贝数据到输入缓冲区
        memcpy(src_data[0], pkt->data, pkt->size);

        // 计算目标样本数（考虑采样率转换）
        int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, in_sample_rate) +
                                                src_nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);

        // 如果目标缓冲区不够大，重新分配
        if (dst_nb_samples > max_dst_nb_samples) {
            av_freep(&dst_data[0]);
            ret = av_samples_alloc(dst_data, &dst_linesize, out_ch_layout.nb_channels,
                                   dst_nb_samples, out_sample_fmt, 1);
            if (ret < 0) {
                fprintf(stderr, "Could not reallocate destination samples\n");
                av_freep(&src_data[0]);
                av_freep(src_data);
                av_packet_unref(pkt);
                break;
            }
            max_dst_nb_samples = dst_nb_samples;
        }

        // 执行重采样：S16 -> S32
        int converted_samples = swr_convert(swr_ctx, dst_data, dst_nb_samples,
                                            (const uint8_t**)src_data, src_nb_samples);

        if (converted_samples < 0) {
            fprintf(stderr, "Error while converting audio in packet %d\n", count);
        } else if (converted_samples > 0) {
            // 计算转换后的数据大小
            int converted_size = av_samples_get_buffer_size(&dst_linesize, out_ch_layout.nb_channels,
                                                            converted_samples, out_sample_fmt, 1);
            if (converted_size > 0) {
                fwrite(dst_data[0], 1, converted_size, outFile);
                printf("Packet %d: input_size=%d, samples=%d->%d, output_size=%d\n",
                       count, pkt->size, src_nb_samples, converted_samples, converted_size);
            }
        }

        // 清理输入缓冲区
        av_freep(&src_data[0]);
        av_freep(src_data);

        av_packet_unref(pkt);
        fflush(outFile);
    }

    if (ret < 0 && ret != AVERROR_EOF) {
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Error reading frames: %s\n", errors);
    }

    fclose(outFile);
    avformat_close_input(&fmt_ctx);
    av_packet_free(&pkt);
    av_dict_free(&options);

    // 清理重采样缓冲区
    if(dst_data) {
        av_freep(&dst_data[0]);
        av_freep(dst_data);
    }

    // 清理声道布局
    av_channel_layout_uninit(&out_ch_layout);
    swr_free(&swr_ctx);

    printf("Audio capture and resampling finished. Output saved as audio_s32.pcm\n");
    return 0;
}
*/
